using System;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.MTS;
using OracleInternal.Network;
using OracleInternal.ServiceObjects;

namespace OracleInternal.TTC
{
	internal class TTCTransactionEN : TTCFunction
	{
		internal const int OTXCOMIT = 1;

		internal const int OTXABORT = 2;

		internal const int OTXPREPA = 3;

		internal const int OTXFORGT = 4;

		internal const int OTXRECOV = 5;

		internal const int OTXMLPRE = 6;

		internal TTCTransactionEN(MarshallingEngine mEngine)
			: base(mEngine, 104, 0)
		{
		}

		private TxnState DoTransaction(int txnOperation, OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint txnFlag, uint timeout, TxnState transactionInState)
		{
			WriteFunctionHeader();
			txnCtx = null;
			WriteTxnOperation(txnOperation, xid, txnCtx, txnFlag, timeout, transactionInState);
			ReadResponse(out var txnState);
			return txnState;
		}

		internal TxnState Prepare(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, TxnState transactionInState)
		{
			return DoTransaction(3, xid, txnCtx, 0u, 0u, transactionInState);
		}

		internal TxnState Commit(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, TxnState transactionInState)
		{
			return DoTransaction(1, xid, txnCtx, 0u, timeout, transactionInState);
		}

		internal TxnState Abort(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, TxnState transactionInState)
		{
			return DoTransaction(2, xid, txnCtx, 0u, timeout, transactionInState);
		}

		internal void WriteTxnOperation(int txnOpCode, OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint txnFlag, uint timeout, TxnState transactionInState)
		{
			m_marshallingEngine.MarshalSWORD(txnOpCode);
			if (txnCtx != null)
			{
				m_marshallingEngine.MarshalPointer();
				m_marshallingEngine.MarshalUB4(txnCtx.Length);
			}
			else
			{
				m_marshallingEngine.MarshalNullPointer();
				m_marshallingEngine.MarshalUB4(0L);
			}
			if (xid != null)
			{
				m_marshallingEngine.MarshalUB4(xid.m_formatID);
				m_marshallingEngine.MarshalUB4(xid.m_gtrid_length);
				m_marshallingEngine.MarshalUB4(xid.m_bqual_length);
				m_marshallingEngine.MarshalPointer();
				m_marshallingEngine.MarshalUB4(xid.m_data.Length);
			}
			else
			{
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalNullPointer();
				m_marshallingEngine.MarshalUB4(0L);
			}
			m_marshallingEngine.MarshalUB4(timeout);
			m_marshallingEngine.MarshalUB4((uint)transactionInState);
			m_marshallingEngine.MarshalPointer();
			if (m_marshallingEngine.NegotiatedTTCVersion >= 4)
			{
				m_marshallingEngine.MarshalUB4(txnFlag);
			}
			if (txnCtx != null)
			{
				m_marshallingEngine.MarshalB1Array(txnCtx);
			}
			if (xid != null)
			{
				m_marshallingEngine.MarshalB1Array(xid.m_data);
			}
		}

		internal void ReadResponse(out TxnState txnState)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)131328, OracleTraceClassName.TTCTransactionEN, OracleTraceFuncName.ReadResponse);
			}
			bool flag = false;
			byte b = 0;
			txnState = TxnState.Error;
			try
			{
				m_marshallingEngine.TTCErrorObject.Initialize();
				while (!flag)
				{
					try
					{
						switch (m_marshallingEngine.UnmarshalSB1())
						{
						case 23:
							ProcessServerSidePiggybackFunction(0);
							break;
						case 8:
							Process_RPA_Message(out txnState);
							break;
						case 15:
							m_marshallingEngine.TTCErrorObject.ReadWarning();
							break;
						case 4:
							flag = true;
							m_marshallingEngine.TTCErrorObject.ReadErrorMessage();
							if (m_marshallingEngine.TTCErrorObject.ErrorCode == 1403)
							{
								m_marshallingEngine.TTCErrorObject.Initialize();
							}
							else
							{
								OracleConnectionImpl.CheckForAnyErrorFromDB(m_marshallingEngine.TTCErrorObject);
							}
							break;
						case 9:
							if (m_marshallingEngine.HasEOCSCapability)
							{
								m_marshallingEngine.m_endOfCallStatus = m_marshallingEngine.UnmarshalUB4();
							}
							m_marshallingEngine.UnmarshalUB4();
							flag = true;
							break;
						default:
							throw new Exception("TTC error");
						}
					}
					catch (NetworkException ex)
					{
						if (ex.ErrorCode != 3111)
						{
							throw;
						}
						m_marshallingEngine.m_oracleCommunication.Reset();
					}
					catch (Exception)
					{
						if (m_marshallingEngine.m_oraBufRdr != null)
						{
							m_marshallingEngine.m_oraBufRdr.ClearState();
						}
						if (!flag)
						{
							m_marshallingEngine.m_oracleCommunication.Break();
							m_marshallingEngine.m_oracleCommunication.Reset();
							continue;
						}
						throw;
					}
				}
			}
			catch (Exception ex3)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268566528, OracleTraceClassName.TTCTransactionEN, OracleTraceFuncName.ReadResponse, ex3);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)131584, OracleTraceClassName.TTCTransactionEN, OracleTraceFuncName.ReadResponse);
				}
			}
		}

		private void Process_RPA_Message(out TxnState txnState)
		{
			txnState = (TxnState)m_marshallingEngine.UnmarshalUB4();
		}
	}
}
